package com.wangyb.wework.service.contact;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.wangyb.wework.bo.WwGroupchatQueryBo;
import com.wangyb.wework.enums.TrackEventEnum;
import com.wangyb.wework.entity.contact.WwContact;
import com.wangyb.wework.entity.contact.WwContactTrack;
import com.wangyb.wework.entity.contact.WwGroupchat;
import com.wangyb.wework.entity.contact.WwGroupchatMember;
import com.wangyb.wework.entity.employee.WwEmployee;
import com.wangyb.wework.mapper.contact.WwGroupchatMapper;
import com.wangyb.wework.service.IWwEmployeeService;
import com.wangyb.wework.utils.WxApiUtils;
import com.wangyb.wework.vo.WwGroupchatVo;
import com.wangyb.wework.wxApi.GroupchatListResp;
import com.wangyb.wework.wxApi.GroupchatResp;
import com.wangyb.wework.wxApi.callback.WxCallbackMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

import static com.wangyb.wework.enums.WxCallbackEventEnum.EVENT_CHAT;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

/**
 * 客户群列表Service业务层处理
 *
 * @Author: wangyb
 * @Date: 2021/7/8 10:58 上午
 */
@Slf4j
@Service
public class WwGroupchatServiceImpl extends ServiceImpl<WwGroupchatMapper, WwGroupchat> implements IWwGroupchatService {
	@Autowired
	private IWwGroupchatService iWwGroupchatService;
	@Autowired
	private IWwGroupchatMemberService iWwGroupchatMemberService;
	@Autowired
	private IWwEmployeeService iWwEmployeeService;
	@Autowired
	private IWwContactTrackService iWwContactTrackService;
	@Autowired
	private IWwContactService iWwContactService;
	@Autowired
	private RedissonClient redissonClient;



	@Override
	public TableDataInfo<WwGroupchatVo> index(Long corpId, WwGroupchatQueryBo queryBo){
		//TODO 还需过滤掉已解散的群
		LambdaQueryWrapper<WwGroupchat> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(WwGroupchat::getCorpId,corpId);
		TableDataInfo<WwGroupchat> data = PageUtils.buildDataInfo(page(PageUtils.buildPage(),wrapper));
		List<WwGroupchat> groupchatList = data.getRows();

		Set<Long> groupchatIdSet = groupchatList.stream().map(c -> c.getId()).collect(toSet());

		Date today = new Date();
		DateTime todayBegin = DateUtil.beginOfDay(today);
		Date todayEnd = today;

		Map<Long, Integer> memberCountMap = iWwGroupchatMemberService.memberCount(groupchatIdSet,1,null,null);
		Map<Long, Integer> memberJoinTodayCountMap = iWwGroupchatMemberService.memberCount(groupchatIdSet,1,todayBegin,todayEnd);
		Map<Long, Integer> memberQuitTodayCountMap = iWwGroupchatMemberService.memberCount(groupchatIdSet,2,todayBegin,todayEnd);

		List<WwGroupchatVo> voList = groupchatList.stream().map(wwGroupchat -> {
			WwGroupchatVo vo = BeanUtil.toBean(wwGroupchat, WwGroupchatVo.class);
			Long groupchatId = wwGroupchat.getId();
			WwEmployee owner = iWwEmployeeService.getById(wwGroupchat.getOwnerId());
			vo.setOwner(owner);
			vo.setMemberNum(memberCountMap.get(groupchatId));
			vo.setJoinNumToday(memberJoinTodayCountMap.get(groupchatId));
			vo.setQuitNumToday(memberQuitTodayCountMap.get(groupchatId));
			return vo;
		}).collect(toList());
		TableDataInfo<WwGroupchatVo> resp = new TableDataInfo<>(voList,data.getTotal());
		return resp;
	}

	@Override
	@Transactional
	public void syncGroupchat(Long corpId){
		SyncGroupchatSummary summary = new SyncGroupchatSummary();
		GroupchatListResp groupchatListResp = WxApiUtils.getGroupchatList(corpId);
		List<GroupchatListResp.GroupChatListRespEntry> remoteGroupchatList = groupchatListResp.getGroupChatList();
		summary.setRemoteGroupchatCnt(remoteGroupchatList.size());

		List<WwGroupchat> localGroupchatList = iWwGroupchatService.lambdaQuery().eq(WwGroupchat::getCorpId, corpId).list();
		summary.setLocalGroupchatCnt(localGroupchatList.size());

		Set<String> localWxChatIdSet = localGroupchatList.stream().map(c -> c.getWxChatId()).collect(toSet());
		Set<String> remoteWxChatIdSet = remoteGroupchatList.stream().map(c -> c.getChatId()).collect(toSet());


		List<GroupchatResp> newChatList = new ArrayList<>();
		List<GroupchatResp> updateChatList = new ArrayList<>();
		Set<String> deleteWxChatIdSet = new HashSet<>();

		remoteGroupchatList.parallelStream().forEach(entry -> {
			GroupchatResp remoteChat = WxApiUtils.getGroupchatInfo(corpId, entry.getChatId());
			String remoteChatId = entry.getChatId();
			if (localWxChatIdSet.contains(remoteChatId)){
				updateChatList.add(remoteChat);
			}else{
				newChatList.add(remoteChat);
			}
		});
		deleteWxChatIdSet = localWxChatIdSet.stream().filter(lc->!remoteWxChatIdSet.contains(lc)).collect(toSet());

		//新增
		newChatList.stream().forEach(resp->{
			addGroupchat(corpId, resp);
		});
		//更新
		updateChatList.forEach(resp->{
			updateGroupchat(corpId, resp);
		});
		//删除 即群解散，标记状态即可,不需要删除
		if (deleteWxChatIdSet.size()>0){
			deleteWxChatIdSet.forEach(id->this.dismissGroupchat(id));
		}
	}
	@Override
	@Transactional
	public void syncGroupchat(Long corpId, String wxChatId){
		GroupchatResp resp = WxApiUtils.getGroupchatInfo(corpId, wxChatId);
		updateGroupchat(corpId,resp);
	}

	/**
	 * 更新群
	 * @param corpId
	 * @param resp
	 */
	@Transactional
	public void updateGroupchat(Long corpId, GroupchatResp resp) {
		WwGroupchat respGroupchat = resp.getGroupChat();
		String wxChatId = respGroupchat.getWxChatId();
		WwGroupchat localGroupchat = getByWxChatId(wxChatId);
		respGroupchat.setId(localGroupchat.getId());
		initRespGroupChat(corpId, respGroupchat);
		iWwGroupchatService.updateById(respGroupchat);

		List<WwGroupchatMember> localMemberList = iWwGroupchatMemberService.listByGroupchatId(localGroupchat.getId());
		Map<String,Long> localWxUserIdMemberIdMap = localMemberList.stream().collect(Collectors.toMap(WwGroupchatMember::getWxUserid,WwGroupchatMember::getId,(value1, value2) -> value2));
		Set<String> localMemberWxUserIdSet = localWxUserIdMemberIdMap.keySet();

		List<WwGroupchatMember> remoteMemberList = respGroupchat.getMemberList();
		remoteMemberList.forEach(m->{
			m.setCorpId(corpId);
			m.setId(localWxUserIdMemberIdMap.get(m.getWxUserid()));
			m.setGroupchatId(localGroupchat.getId());
			m.setAdminStatus(isGroupchatAdmin(respGroupchat,m));
			m.setInvitorWxUserid(m.getInvitor()!=null?m.getInvitor().getUserid():null);
		});

		Set<String> remoteMemberWxUserIdSet = remoteMemberList.stream().map(m -> m.getWxUserid()).collect(toSet());
		List<WwGroupchatMember> updateMemberList = remoteMemberList.stream().filter(rm -> localMemberWxUserIdSet.contains(rm.getWxUserid())).collect(toList());
		List<WwGroupchatMember> newMemberList = remoteMemberList.stream().filter(rm -> !localMemberWxUserIdSet.contains(rm.getWxUserid())).collect(toList());
		Set<String> deleteMemberWxUserIdSet = localMemberWxUserIdSet.stream().filter(id -> !remoteMemberWxUserIdSet.contains(id)).collect(toSet());

		iWwGroupchatMemberService.updateBatchById(updateMemberList);
		iWwGroupchatMemberService.saveBatch(newMemberList);
		if (deleteMemberWxUserIdSet.size()>0){
			iWwGroupchatMemberService.lambdaUpdate()
				.ne(WwGroupchatMember::getStatus,2)
				.in(WwGroupchatMember::getWxUserid,deleteMemberWxUserIdSet)
				.set(WwGroupchatMember::getStatus,2) //更新状态为退群
				.set(WwGroupchatMember::getQuitTime,new Date()) //退群时间
				.update();
		}
	}

	private WwGroupchat getByWxChatId(String wxChatId) {
		return iWwGroupchatService.lambdaQuery().eq(WwGroupchat::getWxChatId, wxChatId).one();
	}

	/**
	 * 添加群
	 * @param corpId
	 * @param resp
	 */
	@Transactional
	public void addGroupchat(Long corpId, GroupchatResp resp) {
		WwGroupchat respGroupchat = resp.getGroupChat();
		initRespGroupChat(corpId, respGroupchat);
		iWwGroupchatService.save(respGroupchat);
		respGroupchat.getMemberList().forEach(m->{
			m.setGroupchatId(respGroupchat.getId());
			m.setCorpId(corpId);
			m.setAdminStatus(isGroupchatAdmin(respGroupchat,m));
			m.setInvitorWxUserid(m.getInvitor()!=null?m.getInvitor().getUserid():null);
		});
		iWwGroupchatMemberService.saveBatch(respGroupchat.getMemberList());
	}

	/**
	 * 解散群
	 * @param wxChatId
	 */
	@Transactional
	public void dismissGroupchat(String wxChatId){
		iWwGroupchatService.lambdaUpdate()
			.set(WwGroupchat::getState,-1)
			.eq(WwGroupchat::getWxChatId,wxChatId)
			.update();
	}

	private void initRespGroupChat(Long corpId, WwGroupchat respGroupchat) {
		respGroupchat.setCorpId(corpId);
		WwEmployee employee = iWwEmployeeService.lambdaQuery().eq(WwEmployee::getWxUserId, respGroupchat.getOwnerWxUserid()).eq(WwEmployee::getCorpId, corpId).one();
		if (employee != null){
			respGroupchat.setOwnerId(employee.getId());
		}
	}

	/**
	 * 群成员是否为群管理员，1-是群管理员，0-不是群管理员
	 * @param groupchat
	 * @param member
	 * @return
	 */
	private int isGroupchatAdmin(WwGroupchat groupchat,WwGroupchatMember member){
		JSONArray adminArray = JSONArray.parseArray(groupchat.getAdminList());
		for (int i=0;i<adminArray.size();i++){
			JSONObject adminUser = adminArray.getJSONObject(i);
			if (StringUtils.equals(adminUser.getString("userid"),member.getWxUserid())){
				return 1;
			}
		}
		return 0;
	}
	@PostConstruct
	public void subscribe(){
		RTopic topic = redissonClient.getTopic(EVENT_CHAT.name());
		topic.addListener(WxCallbackMsg.class, new MessageListener<WxCallbackMsg>() {
			@Override
			public void onMessage(CharSequence channel, WxCallbackMsg msg) {
				//群创建
				if ("create".equals(msg.getChangType())){
					onGroupchatCreate(msg);
				}
				//群更新 包含群名变更，群成员增加或移除，群主变更，群公告变更
				else if ("update".equals(msg.getChangType())){
					onGroupchatUpdate(msg);
				}
				//群解散
				else if("dismiss".equals(msg.getChangType())){
					onGroupchatDismiss(msg);
				}
			}
		});
	}
	/**
	 * 响应群创建事件
	 * @param msg
	 */
	@Override
	public void onGroupchatCreate(WxCallbackMsg msg){
		Long corpId = msg.getCorpId();
		String chatId = msg.getString("chatId");
		GroupchatResp remoteChat = WxApiUtils.getGroupchatInfo(corpId,chatId);
		addGroupchat(corpId,remoteChat);
	}

	/**
	 * 响应群更新事件 包含群名变更，群成员增加或移除，群主变更，群公告变更
	 * @param msg
	 */
	@Override
	public void onGroupchatUpdate(WxCallbackMsg msg){
		String updateDetail = msg.getString("UpdateDetail");
		//退群
		if ("del_member".equals(updateDetail)) {
			delMember(msg);
		}
		//新入群
		else if ("add_member".equals(updateDetail)){
			addMember(msg);
		}
		//群主变更
		else if ("change_owner".equals(updateDetail)){
			changeOwner(msg);
		}
		//群名称变更
		else if("change_name".equals(updateDetail)){
			changeName(msg);
		}
		//群公告变更
		else if ("change_notice".equals(updateDetail)){
			changeNotice(msg);
		}
	}
	private WwGroupchat getRemoteGroupchat(WxCallbackMsg msg){
		Long corpId = msg.getCorpId();
		String chatId = msg.getString("chatId");
		GroupchatResp remoteChatResp = WxApiUtils.getGroupchatInfo(corpId,chatId);
		return remoteChatResp.getGroupChat();
	}

	private void changeNotice(WxCallbackMsg msg) {
		WwGroupchat groupchat = getRemoteGroupchat(msg);
		log.debug("群公告变更");
		iWwGroupchatService.lambdaUpdate()
			.set(WwGroupchat::getNotice, groupchat.getNotice())
			.eq(WwGroupchat::getWxChatId, groupchat.getWxChatId())
			.update();
	}

	private void changeName(WxCallbackMsg msg) {
		log.debug("群名称变更");
		WwGroupchat groupchat = getRemoteGroupchat(msg);
		iWwGroupchatService.lambdaUpdate()
			.set(WwGroupchat::getName, groupchat.getName())
			.eq(WwGroupchat::getWxChatId, groupchat.getWxChatId())
			.update();
	}

	private void changeOwner(WxCallbackMsg msg) {
		WwGroupchat groupchat = getRemoteGroupchat(msg);
		log.debug("群主变更");
		String owerWxUserId = groupchat.getOwnerWxUserid();
		WwEmployee employee = iWwEmployeeService.getByWxUserid(owerWxUserId);
		iWwGroupchatService.lambdaUpdate()
			.set(WwGroupchat::getOwnerId,employee.getId())
			.set(WwGroupchat::getOwnerWxUserid,owerWxUserId)
			.eq(WwGroupchat::getWxChatId, groupchat.getWxChatId())
			.update();
	}

	private void delMember(WxCallbackMsg msg) {
		WwGroupchat groupchat = getRemoteGroupchat(msg);
		Integer quitScene = msg.getInteger("QuitScene");
		List<WwGroupchatMember> remoteMemberList = groupchat.getMemberList();
		Set<String> remoteWxUserIdSet = remoteMemberList.stream().map(WwGroupchatMember::getWxUserid).collect(toSet());
		WwGroupchat localGroupchat = getByWxChatId(groupchat.getWxChatId());
		List<WwGroupchatMember> localMemberList = iWwGroupchatMemberService.listByGroupchatId(localGroupchat.getId());
		List<WwGroupchatMember> quitList = localMemberList.stream()
			.filter(local -> !remoteWxUserIdSet.contains(local.getWxUserid()))
			.map(local -> {
				local.setQuitTime(msg.getCreateTime());
				local.setQuitScene(quitScene);
				local.setStatus(2); //退群
				return local;
			}).collect(toList());
		iWwGroupchatMemberService.updateBatchById(quitList);


		//添加退群轨迹
		List<WwContactTrack> trackList = quitList.stream().map(member -> {
			WwContactTrack track = new WwContactTrack();
			if (member.getType() == 1){
				//TODO 员工退群
				//员工退群，取通讯录表 ww_employee
			}else if(member.getType() == 2){
				//外部联系人，取ww_contact表
				WwContact contact = iWwContactService.getContactByWxUserid(member.getWxUserid());
				if (contact != null){
					track.setContactId(contact.getId());
					track.setContactWxUserid(contact.getWxExternalUserid());
				}
			}
			track.setEvent(TrackEventEnum.GROUPCHAT_QUIT);
			track.setCreateTime(msg.getCreateTime());
			track.setCorpId(member.getCorpId());
			track.setFrom(msg.getFromUserName());
			//TODO 退群消息
			JSONObject content = new JSONObject();
			content.put("groupchatId",localGroupchat.getId());
			content.put("groupchatName",localGroupchat.getName());
			content.put("groupchatOwnerId",localGroupchat.getOwnerId());
			content.put("quitScene",quitScene);
			content.put("quitTime",msg.getCreateTime());
			track.setContent(content.toJSONString());
			return track;
		}).collect(toList());
		iWwContactTrackService.saveBatch(trackList);
	}

	private void addMember(WxCallbackMsg msg) {
		WwGroupchat groupchat = getRemoteGroupchat(msg);
		List<WwGroupchatMember> remoteMemberList = groupchat.getMemberList();
		//TODO 本地可能还没有创建群
		WwGroupchat localGroupchat = getByWxChatId(groupchat.getWxChatId());
		List<WwGroupchatMember> localMemberList = iWwGroupchatMemberService.listByGroupchatId(localGroupchat.getId());
		Set<String> localWxUserIdSet = localMemberList.stream().map(WwGroupchatMember::getWxUserid).collect(toSet());
		List<WwGroupchatMember> addList = remoteMemberList.stream()
			.filter(remote->!localWxUserIdSet.contains(remote.getWxUserid()))
			.map(m->{
				m.setCorpId(msg.getCorpId());
				m.setGroupchatId(localGroupchat.getId());
				m.setAdminStatus(isGroupchatAdmin(groupchat,m));
				m.setInvitorWxUserid(m.getInvitor()!=null?m.getInvitor().getUserid():null);
				return m;
			}).collect(toList());
		iWwGroupchatMemberService.saveBatch(addList);

		//添加入群轨迹
		List<WwContactTrack> trackList = addList.stream().map(member -> {
			WwContactTrack track = new WwContactTrack();
			if (member.getType() == 1){
				//TODO 员工入群，取通讯录表 ww_employee
			}else if(member.getType() == 2){
				//外部联系人，取ww_contact表
				WwContact contact = iWwContactService.getContactByWxUserid(member.getWxUserid());
				if (contact != null){
					track.setContactId(contact.getId());
					track.setContactWxUserid(contact.getWxExternalUserid());
				}
			}
			track.setEvent(TrackEventEnum.GROUPCHAT_JOIN);
			track.setCreateTime(msg.getCreateTime());
			track.setCorpId(member.getCorpId());
			track.setFrom(msg.getFromUserName());
			//TODO 退群消息
			JSONObject content = new JSONObject();
			content.put("groupchatId",localGroupchat.getId());
			content.put("groupchatName",localGroupchat.getName());
			content.put("groupchatOwnerId",localGroupchat.getOwnerId());
			content.put("invitorWxUserId",member.getInvitorWxUserid());
			content.put("joinScene",member.getJoinScene());
			content.put("joinTime",member.getJoinTime());
			track.setContent(content.toJSONString());
			return track;
		}).collect(toList());
		iWwContactTrackService.saveBatch(trackList);
	}

	/**
	 * 响应群解散事件
	 * @param msg
	 */
	@Override
	public void onGroupchatDismiss(WxCallbackMsg msg){
		String chatId = msg.getString("chatId");
		dismissGroupchat(chatId);
	}
}
